package vip.housir.kotlindemo.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.TypeHandler;

import java.io.IOException;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

@MappedJdbcTypes(JdbcType.VARCHAR)
public class JSONTypeHandler implements TypeHandler<Object> {

    /**
     * json数据和类名的分隔符号
     */
    private static final char TypeSPLIT = '/';
    private static final char KotlinSPLIT = '$';

    private ObjectMapper objectMapper;

    public JSONTypeHandler() {
        this.objectMapper = new ObjectMapper();
    }

    /**
     * json 转换成对象
     */
    private Object jsonToObject(String json) throws RuntimeException {
        if (json == null) {
            return null;
        }
        int index = json.lastIndexOf(TypeSPLIT);
        if (index < 0) {
            return null;
        }
        String typeKey = json.substring(index + 1);
        json = json.substring(0, index);

        // fix bug for kotlin such as java.util.Collections$SingletonMap java.util.Arrays$ArrayList
        int indexTmp = typeKey.lastIndexOf(KotlinSPLIT);
        if (indexTmp > 0) {
            typeKey = "java.util." + typeKey.substring(indexTmp + 1);
        }
        Class<?> cls;
        try {
            cls = Class.forName(typeKey);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("序列化成json时找不到指定的类", e);
        }
        Object object;
        try {
            object = objectMapper.readValue(json, cls);
        } catch (IOException e) {
            throw new RuntimeException("序列化成json时失败", e);
        }
        return object;
    }

    public void setParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
        if (parameter == null) {
            ps.setString(i, null);
            return;
        }
        String json;
        try {
            json = objectMapper.writeValueAsString(parameter);
        } catch (IOException e) {
            throw new RuntimeException("序列化成json时失败", e);
        }
        json = json + TypeSPLIT + parameter.getClass().getName();
        ps.setString(i, json);
    }

    public Object getResult(ResultSet rs, String columnName) throws SQLException {
        String json = rs.getString(columnName);
        return jsonToObject(json);
    }

    public Object getResult(ResultSet rs, int columnIndex) throws SQLException {
        String json = rs.getString(columnIndex);
        return jsonToObject(json);
    }

    public Object getResult(CallableStatement cs, int columnIndex) throws SQLException {
        String json = cs.getString(columnIndex);
        return jsonToObject(json);
    }
}


